#include "LogManager.h"

#include "Thread.h"
#include "Logger.h"
#include "Guard_T.h"
#include "LogToFiles.h"
#include "LogToStdout.h"

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

// The members must be sort by <output_t>
static const char *OutputMode[] = 
{
    "NULL",	 	 // 0
    "STDOUT",    // 1
    "FILES"	 	 // 2
};
static const char *LogItems[] =
{
    "LL_TRACE",
    "LL_DEBUG",
    "LL_WNING",
    "LL_ERROR",
    "LL_RINFO",
    "LL_FATAL",
};
const size_t LogItemsNum = sizeof(LogItems)/sizeof(LogItems[0]);
static const char *LogLevelList[] =
{
    "SHUTDOWN",   // LL_SHUTDOWN == 0x0001 << index
    "TRACE",	  // LL_TRACE    == 0x0001 << index
    "DEBUG",      // LL_DEBUG    == 0x0001 << index
    "WNING",	  // LL_WNING    == 0x0001 << index
    "ERROR",	  // LL_ERROR    == 0x0001 << index
    "RINFO",	  // LL_RINFO    == 0x0001 << index
    "FATAL",      // LL_FATAL    == 0x0001 << index
    "ALLS"
};
static const char *GenerateFilePeriod[] =
{
    "",
    "HOURLY",
    "DAILY",
    "WEEKLY"
};
char *LogManager::Output::log_dir_ = new char[NDK_MAX_PATH_LEN + 1];
int LogManager::Output::output_mode_ = 0;//LogManager::Output::OM_NULL;

void LogManager::Output::reset ()
{
    LogManager::Output::output_mode_ = 0;//LogManager::Output::OM_NULL;
    memset (LogManager::Output::log_dir_, '\0', NDK_MAX_PATH_LEN + 1);
    strcpy (LogManager::Output::log_dir_, "./");
}
// --------------------------------------------------------------------
LogManager::KeyValue::KeyValue ()
: value (0)
, key (0)
{
    key = new char[MAX_MODULE_NAME_LEN + 1];
    memset (key, '\0', MAX_MODULE_NAME_LEN + 1);
}
LogManager::KeyValue::~KeyValue ()
{
	if (this->key)
		delete []this->key;
	this->key = 0;
	this->value = 0;
}
LogManager::KeyValue &LogManager::KeyValue::operator = (const KeyValue &kv)
{
	this->value = kv.value;
	strncpy (this->key, kv.key, MAX_MODULE_NAME_LEN);
	return *this;
}
// --------------------------------------------------------------------
LogManager::Modules::Modules ()
: modules_num_ (0)
, list_size_ (0)
, modules_list_ (0)
{
}
LogManager::Modules::~Modules ()
{
	if (this->modules_list_)
		delete []this->modules_list_;
	this->modules_list_ = 0;
	this->list_size_ = 0;
	this->modules_num_ = 0;
}
void LogManager::Modules::reset ()
{
	if (this->list_size_ == 0)
	{
		// preallocate 8 modules
		this->modules_list_ = new KeyValue[8];
		this->list_size_ = 8;
	}else
	{
		for (int i = 0; i < this->list_size_; ++i)
		{
			memset (this->modules_list_[i].key, '\0', MAX_MODULE_NAME_LEN);
			this->modules_list_[i].value = 0;
		}
	}
	this->modules_num_ = 0;
}
int LogManager::Modules::insert (const char *module, int val)
{
	if (module == 0) return -1;

	if (this->modules_num_ >= this->list_size_)
	{
		int size = this->list_size_ + 4;
		KeyValue *kv = new KeyValue[size];
		for (int i = 0; i < this->list_size_; ++i)
		{
			kv[i] = this->modules_list_[i];
		}
		delete []this->modules_list_;
		this->modules_list_ = kv;
		this->list_size_ = size;
	}
	this->modules_list_[this->modules_num_].value = val;
	strncpy (this->modules_list_[this->modules_num_].key,
			module,
			MAX_MODULE_NAME_LEN);
	++this->modules_num_;
	return 0;
}
int LogManager::Modules::get_llevel (const char *module)
{
	for (int i = 0; i < this->modules_num_; ++i)
	{
		if (strcmp (module, this->modules_list_[i].key) == 0)
			return this->modules_list_[i].value;
	}
	return -1;
}
// ------------------------------------------------------------------
LogManager::Strategy::Strategy ()
{
	this->reset ();
}
void LogManager::Strategy::reset (void)
{
	this->check_config_interval_ = 5;
	this->generate_file_period_ = GP_DISABLE;
	this->period_count_ = 1;
	this->single_file_size_ = 1024 * 1024;
	this->max_rolloever_index_ = 5;
	memset (this->file_name_, '\0', sizeof(this->file_name_));
}
LogManager::Strategy &LogManager::Strategy::operator = (const Strategy &s)
{
	this->check_config_interval_ = s.check_config_interval_;
	this->generate_file_period_  = s.generate_file_period_;
	this->period_count_ = s.period_count_;
	this->single_file_size_ = s.single_file_size_;
	this->max_rolloever_index_ = s.max_rolloever_index_;
	memcpy (this->file_name_, s.file_name_, NDK_MAX_FILENAME_LEN);

	return *this;
}
// ------------------------------------------------------------------
LogManager::LogRecord::LogRecord ()
: max_len_of_one_record_ (512)
{
	memset (this->record_format_, '\0', sizeof (this->record_format_));
}
void LogManager::LogRecord::reset (void)
{
	memset (this->record_format_, '\0', sizeof (this->record_format_));
}
// ------------------------------------------------------------------
LogManager *LogManager::instance_ = 0;
LogManager::LogManager ()
: curr_size_ (0)
, config_filename_ (0)
, file_path_ (0)
, log_record_ (0)
, root_node_ (0)
, stdout_output_ (0)		
, files_output_ (0)		
{
}
LogManager::~LogManager ()
{
	if (this->config_filename_)
		delete []this->config_filename_;
	this->config_filename_ = 0;
}
LogManager *LogManager::instance ()
{
	// No lock
	if (LogManager::instance_ == 0)
	{
		LogManager::instance_ = new LogManager();
	}
	return LogManager::instance_;
}
int LogManager::init (const char *config_name)
{
    Guard_T<ThreadMutex> guard (this->log_mutex_);
	this->last_check_time_  = time(0);
	this->config_filename_  = new char[NDK_MAX_FILENAME_LEN + 1];
	memset (this->config_filename_, '\0', NDK_MAX_FILENAME_LEN + 1);

	strncpy (this->config_filename_, config_name, NDK_MAX_FILENAME_LEN);

	// access config file
	if (::stat (this->config_filename_, &this->st_buff_) != 0)
	{
		fprintf (stderr, "get %s file stat error\n", 
				this->config_filename_);
		return -1;
	}
	this->last_modify_time_ = this->st_buff_.st_mtime;

	return this->load_config ();
}
int LogManager::update_config (void)
{
	time_t now = time (0);
	if (difftime (now, this->last_check_time_) 
			< this->strategy_.check_config_interval_)
		return 0;
	// Lock  !!!
	this->last_check_time_ = now;

	// access config file
	if (::stat (this->config_filename_, &this->st_buff_) != 0)
		return -1;

	// If config file is not modified, not change log strategy
	if (this->st_buff_.st_mtime == this->last_modify_time_)
		return 0;

	this->last_modify_time_ = this->st_buff_.st_mtime;

	// reload config file
	return this->load_config ();
}
int LogManager::load_config ()
{
	dictionary *ini = 0;
	ini = iniparser_load (this->config_filename_);
	if (ini == 0)
	{
		fprintf (stderr, "cannot parse file: %s\n", 
				this->config_filename_);
		return -1;
	}
#ifdef NDK_LOG_DEBUG
	iniparser_dump (ini, stderr);
#endif

	// [Output]
	if (this->load_cfg_output (ini) != 0)
		return -1;

	// [Module]
	if (this->load_cfg_modules (ini) != 0)
		return -1;

	// [Strategy]
	if (this->load_cfg_strategy (ini) != 0)
		return -1;

	// [LogRecord]
	if (this->load_cfg_lrecord (ini) != 0)
		return -1;

#ifdef NDK_LOG_DEBUG
	this->dump_cfg ();
#endif
	return this->apply_config ();
}
int LogManager::load_cfg_output (dictionary *ini)
{
	// !! init
	Output::reset ();

	char *saveptr = 0;
	char *token   = 0;
	char *str     = 0;
	//
	// 1. log_dir
	char *log_dir = iniparser_getstring (ini, "Output:log_dir", 0);
	if (log_dir && strlen (log_dir) > 0) // defined and has value
	{
		strncpy (Output::log_dir_, log_dir,  NDK_MAX_PATH_LEN);  
	}

	// 2. output 
	char *output = iniparser_getstring (ini, "Output:output", 0);
	if (output && strlen (output) > 0)  // defined and has value
	{
		for (str = output; ; str = 0)
		{
			token = NDK::strtok (str, "|", &saveptr);
			if (token == 0)
				break;
			for (size_t i = 0; 
					i < sizeof(OutputMode) / sizeof(OutputMode[0]); 
					++i)
			{
				if (strcmp (token, OutputMode[i]) == 0)
					NDK_SET_BITS (Output::output_mode_, 0x0001 << i);
			}
		}
	}
	return 0;
}
int LogManager::load_cfg_modules (dictionary *ini)
{
	char *saveptr = 0;
	char *token   = 0;
	char *str     = 0;
	//
	this->modules_.reset ();

	// 1. modules
	char **modules_list = 0;
	int modules_num = 0;
	char  module_name[MAX_MODULE_NAME_LEN + 1] = {0};
	char *modules = iniparser_getstring (ini, "Module:modules", 0);
	if (modules && strlen (modules) > 0) // defined and has value
	{
		int mlen = strlen (modules);
		char *pb = new char[mlen + 1];
		memset (pb, '\0', mlen + 1);
		strncpy (pb, modules, mlen);
		for (str = pb; ; str = 0)
		{
			token = NDK::strtok (str, ":", &saveptr);
			if (token == 0)
				break;
			++modules_num;
		}
		delete []pb;

		++modules_num;  // for 'root'
#ifdef NDK_LOG_DEBUG
		fprintf (stderr, "module num = %d\n", modules_num);
#endif
		modules_list = new char*[modules_num];
		int i = 0;
		modules_list[i] = new char[MAX_MODULE_NAME_LEN + 1];
		memset (modules_list[i], '\0', MAX_MODULE_NAME_LEN + 1);
		strcpy (modules_list[i], ROOT_MODULE_NAME);
		++i;
		for (str = modules; i < modules_num; str = 0, ++i)
		{
			token = NDK::strtok (str, ":", &saveptr);
			if (token == 0)
				break;
			modules_list[i] = new char[MAX_MODULE_NAME_LEN + 1];
			memset (modules_list[i], '\0', MAX_MODULE_NAME_LEN + 1); 
			memset (module_name, '\0', sizeof(module_name));
			NDK::strstrip_all (token, module_name, MAX_MODULE_NAME_LEN);
			strncpy (modules_list[i], module_name, MAX_MODULE_NAME_LEN);
		}
	}
	// 2. get concrete modules
	char *llevel = 0;
	static char  module_sec[] = "Module:";
	memset (module_name, '\0', sizeof(module_name));
	for (int i = 0; i < modules_num; ++i)
	{
		strcpy (module_name, module_sec);
		memset (module_name + sizeof(module_sec) - 1, 
				'\0', 
				sizeof(module_name) - sizeof(module_sec) + 1);
		strncpy (module_name + sizeof(module_sec) - 1,
				modules_list[i], 
				MAX_MODULE_NAME_LEN - sizeof(module_sec));
#ifdef NDK_LOG_DEBUG
		fprintf (stderr, "module-name %s\n", module_name);
#endif
		llevel = iniparser_getstring (ini, module_name, 0);
		int level = 0;
		if (llevel && strlen (llevel) > 0) // defined and has value
		{
			// convert "TRACE" to int;
#ifdef NDK_LOG_DEBUG
			fprintf (stderr, "module list[%d] : %s [", i, modules_list[i]);
#endif
            if (strstr (llevel, "ALLS") != 0)
            {
                NDK_SET_BITS (level, LL_ALLS);
#ifdef NDK_LOG_DEBUG
                fprintf (stderr, "%s|", "ALLS");
#endif
            }
			for (size_t j = 0; 
					j < sizeof(LogLevelList) / sizeof(LogLevelList[0]);
					++j)
			{
				if (strcmp (LogLevelList[j], "ALLS") != 0
						&& strstr (llevel, LogLevelList[j]))
				{
					NDK_SET_BITS (level, 0x0001 << j);
#ifdef NDK_LOG_DEBUG
					fprintf (stderr, "%s|", LogLevelList[j]);
#endif
				}
			}
#ifdef NDK_LOG_DEBUG
			fprintf (stderr, "\b]\n");
#endif

			// Insert "root."
			memset (module_name, '\0', sizeof(module_name));
			if (strstr (modules_list[i], ROOT_MODULE_NAME) == 0)
			{
				strcpy  (module_name, ROOT_MODULE_NAME".");
				strncat (module_name, modules_list[i], MAX_MODULE_NAME_LEN);
				this->modules_.insert (module_name, level);
			}else
			{
				this->modules_.insert (modules_list[i], level);
			}
		}
	}
	// Release memory
	if (modules_list)
	{
		for (int n = 0; n < modules_num; ++n)
			delete []modules_list[n];
		delete []modules_list;
	}

	return 0;
}
int LogManager::load_cfg_strategy (dictionary *ini)
{
	// Init
	this->strategy_.reset ();

	// 1. check_config_interval
	char *interval = iniparser_getstring (ini, 
			"Strategy:check_config_interval", 0);
	int value = 0;
	if (interval && strlen (interval) > 0)
	{
		value = atoi (interval);
		if (strchr (interval, 'm') || strchr (interval, 'M'))
			value *= 60;
	}
	if (value <= 0)
	{
		value = 5;
		fprintf (stderr, "You didn't config <check_config_interval>, so use"
				" default value <%dsec>\n", value);
	}
	this->strategy_.check_config_interval_ = value;

	// 2. generate_file_period
	char *period = iniparser_getstring (ini, "Strategy:generate_file_period", 0);
	value = 0;
	if (period && strlen (period) > 0)
	{
		for (size_t i = 1; 
				i < sizeof(GenerateFilePeriod)/sizeof(GenerateFilePeriod[0]);
				++i)
		{
			if (strcmp (period, GenerateFilePeriod[i]) == 0)
			{
				this->strategy_.generate_file_period_ = i;
				break;
			}
		}
	}

	// 3. count
	this->strategy_.period_count_ = iniparser_getint (ini, "Strategy:count", 1);

	// 4. file_name
	char *fname = iniparser_getstring (ini, "Strategy:file_name", 0);
	if (fname && strlen (fname) > 0)
	{
		strncpy (this->strategy_.file_name_, fname, NDK_MAX_FILENAME_LEN);
	}

	// 5. single_file_size
	char *fsize = iniparser_getstring (ini, "Strategy:single_file_size", 0);
	value = 0;
	if (fsize && strlen (fsize) > 0)
	{
		value = atoi (fsize);
		if (strrchr (fsize, 'k') || strrchr (fsize, 'K'))
			value *= 1024;
		else
			value *= 1024 * 1024;
	}
	// Default is 1M
	if (value <= 0)
		value = 1 * 1024 * 1024;
	this->strategy_.single_file_size_ = value;

	// 6. max_rolloever_index
	this->strategy_.max_rolloever_index_ 
		= iniparser_getint (ini, "Strategy:max_rolloever_index", 5);

	return 0;
}
int LogManager::load_cfg_lrecord (dictionary *ini)
{
	// Init
	this->lrecord_cfg_.reset ();

	// 1. record_format
	char *fmt = iniparser_getstring (ini, "LogRecord:record_format", 0);
	if (fmt && strlen (fmt) > 0)
	{
		// Parse format
	}
	// "[%date %time.%msec][%thr]<%level><%module>:"

	// 2. max_len_of_one_record
	int limit = iniparser_getint (ini, 
			"LogRecord:max_len_of_one_record", 
			512);
	if (limit <= 0) limit = 512;
	// Apply config
	if (this->lrecord_cfg_.max_len_of_one_record_ < limit)
	{
		if (this->log_record_)
			delete []this->log_record_;
		this->log_record_ = 0;
	}
	if (this->log_record_ == 0)
	{
		this->log_record_ = new char[limit + 2];
		memset (this->log_record_, '\0', limit + 2);
	}
	this->lrecord_cfg_.max_len_of_one_record_ = limit;

	return 0;
}
int LogManager::apply_config ()
{
	// [Output]

	// [Module] 
	Logger *l = this->root_node_;
	while (l)
	{
		this->apply_module_cfg (l);
		l = l->next ();
	}

	// [Strategy]
	this->apply_strategy_cfg ();

	// [LogRecord]
	return 0;
}
int LogManager::apply_strategy_cfg (void)
{
	// build 
	if (NDK_BIT_ENABLED (LogManager::Output::output_mode_,
				LogManager::Output::OM_FILES))
	{
		if (this->files_output_ == 0)
		{
			this->files_output_ = new LogToFiles();
			this->files_output_->open (Output::log_dir_, &this->strategy_);
		}else
		{
			this->files_output_->update_strategy (Output::log_dir_,
					&this->strategy_);
		}
	}else
	{
		if (this->files_output_)
		{
			delete this->files_output_;
			this->files_output_ = 0;
		}
	}
	if (NDK_BIT_ENABLED (LogManager::Output::output_mode_,
				LogManager::Output::OM_STDOUT))
	{
		if (this->stdout_output_ == 0)
		{
			this->stdout_output_ = new LogToStdout();
			this->stdout_output_->open (0, &this->strategy_);
		}else
		{
			this->stdout_output_->update_strategy (0,
					&this->strategy_);
		}
	}else
	{
		if (this->stdout_output_)
		{
			delete this->stdout_output_;
			this->stdout_output_ = 0;
		}
	}
	return 0;
}
int LogManager::get_parent_llevel (const char *str, char *parent)
{
	if (str == 0) return 0;
	char *pos = strrchr (str, '.');
	int l = 0;
	l = this->modules_.get_llevel (str);
	if (l == -1) l = 0;
	char s[MAX_MODULE_NAME_LEN + 1] = {0};
	if (pos) // grade
	{
		strncpy (parent, str, pos - str); 
#ifdef NDK_LOG_DEBUG
		fprintf (stderr, "parent = %s\n", parent);
#endif
		return l | this->get_parent_llevel (parent, s);
	}
	return l;
}
int LogManager::apply_module_cfg (Logger *l)
{
	// [Module] 
	int llevel = -1;
	char name[MAX_MODULE_NAME_LEN + 1] = {0};
	llevel = this->modules_.get_llevel (l->module_name ());
	if (llevel != -1)
		l->log_level (llevel);
	else
		l->log_level (0);
	// Get parent llevel
	llevel = this->get_parent_llevel (l->module_name (), name);
	if (llevel != -1)
		l->parent_llevel (llevel);
	else
		l->parent_llevel (0);

	return 0;
}
Logger *LogManager::get_logger (const char *module_name)
{
	if (module_name == 0 ||
			strlen (module_name) == 0)
		return 0;

	char name[MAX_MODULE_NAME_LEN + 1] = {0};
	char *p = name;
	if (strstr (module_name, ROOT_MODULE_NAME) == 0)
	{
		strcpy  (p, ROOT_MODULE_NAME".");
		strncat (p, module_name, MAX_MODULE_NAME_LEN);
	}else
	{
		p = const_cast<char *>(module_name);
	}
	// Lock here
    Guard_T<ThreadMutex> guard (this->log_mutex_);
	// Find exist logger first.
	Logger *itor = this->root_node_;
	while (itor)
	{
		if (strcmp (itor->module_name (), p) == 0)
		{
#ifdef NDK_LOG_DEBUG
			fprintf (stderr, "Find a exist logger: %s\n",
					itor->module_name ());
#endif
			return itor;
		}
		itor = itor->next ();
	}

	Logger *l = new Logger (this, p);
	if (l == 0) return 0;
	if (this->apply_module_cfg (l) == 0)
	{
		this->insert_logger (l);
#ifdef NDK_LOG_DEBUG
		fprintf (stderr, "Allocate a logger : %s\n",
				l->module_name ());
		fprintf (stderr, "%s llevel -> [", l->module_name ());
		for (size_t j = 0; 
				j < sizeof(LogLevelList) / sizeof(LogLevelList[0]);
				++j)
		{
			if (NDK_BIT_ENABLED (l->log_level (), 0x0001 << j))
				fprintf (stderr, "%s|", LogLevelList[j]);
		}
		fprintf (stderr, "\b] parent llevel -> [");
		for (size_t j = 0; 
				j < sizeof(LogLevelList) / sizeof(LogLevelList[0]);
				++j)
		{
			if (NDK_BIT_ENABLED (l->parent_llevel (), 0x0001 << j))
				fprintf (stderr, "%s|", LogLevelList[j]);
		}
		fprintf (stderr, "\b]\n");
#endif
		return l;
	}
	delete l;
	return 0;
}
int LogManager::insert_logger (Logger *l)
{
	Logger *itor = this->root_node_;
	if (itor == 0)
	{
		this->root_node_ = l;
		return 0;
	}
	while (itor->next ())
		itor = itor->next ();

	itor->next (l);
	return 0;
}
namespace log_help_
{
	static int get_bit (int n)
	{
		for (size_t i = 1; i < sizeof(int) * 8; ++i)
		{
			if ((n >> i) & 0x0001)
			{
				return i;
			}
		}
		return 0;
	}
}
int LogManager::log (Logger *log, 
		int ll, 
		const char *format,
		va_list &va_ptr)
{
	// Lock from here !!
    Guard_T<ThreadMutex> guard (this->log_mutex_);
	this->update_config ();

	if (LogManager::Output::output_mode_ == LogManager::Output::OM_NULL)
		return 0;

	if (log->shutdown () ||
			!log->enable_for (ll))
		return 0;

	// Format
	this->current_time_.gettimeofday ();
	this->current_dtime_.update (this->current_time_.sec ());
	this->current_dtime_.time_to_str(this->log_time_, 
			sizeof(this->log_time_));
	this->current_time_.sec (0);
	int len = 0;
	int bit = log_help_::get_bit (ll);
	if (bit == 0)
	{
		fprintf (stderr, "The parameter log-level(%d) is invalid\n", ll);
		return 0;
	}
	ll = (log_help_::get_bit (ll) - 1) % LogItemsNum;
	memset (this->log_record_, '\0', 
			this->lrecord_cfg_.max_len_of_one_record_);
	int ret = snprintf (this->log_record_, 
			this->lrecord_cfg_.max_len_of_one_record_ + 1, 
			"[%s.%03lu][%lu]<%s><%s>: ",

			this->log_time_,
			this->current_time_.msec (),
			Thread::self (),
			LogItems[ll],
			log->module_name () + sizeof (ROOT_MODULE_NAME));
	if (ret >= this->lrecord_cfg_.max_len_of_one_record_ + 1)
		ret = this->lrecord_cfg_.max_len_of_one_record_;
	len += ret;
	if (len < this->lrecord_cfg_.max_len_of_one_record_)
	{
		ret = vsnprintf (this->log_record_ + len, 
				this->lrecord_cfg_.max_len_of_one_record_ + 1 - len,
				format,
				va_ptr);
		//va_end (va_ptr);
		if (ret < 0) return -1;
		/**
		 * check overflow or not
		 * Note : snprintf and vnprintf return value is the number of characters
		 * (not including the trailing ’\0’) which would have been  written  to 
		 * the  final  string  if enough space had been available.
		 */
		if (ret >= (this->lrecord_cfg_.max_len_of_one_record_ + 1 - len))
			ret = this->lrecord_cfg_.max_len_of_one_record_ + 1 - len - 1;
		// vsnprintf return the length of <va_ptr> actual
		len += ret;
	}
	this->log_record_[len] = '\n';
	//
	int result = 0;
	if (NDK_BIT_ENABLED (LogManager::Output::output_mode_,
				LogManager::Output::OM_FILES))
	{
		result = this->files_output_->log (this->log_record_, len + 1);
	}
	if (NDK_BIT_ENABLED (LogManager::Output::output_mode_,
				LogManager::Output::OM_STDOUT))
	{
		result = this->stdout_output_->log (this->log_record_, len + 1);
	}
	return result;
}
void LogManager::dump_cfg (void)
{
	fprintf (stderr, "-------------------------------------------\n"
			"output:log_dir = [%s]\n"
			,
			LogManager::Output::log_dir_);

	fprintf (stderr, "output:output  = [");
	for (size_t i = 0; i < sizeof(OutputMode)/sizeof(OutputMode[0]); ++i)
	{
		if (NDK_BIT_ENABLED (Output::output_mode_, 0x0001 << i))
			fprintf (stderr, "%s|", OutputMode[i]);
	}
	fprintf (stderr, "\b]\n");

	fprintf (stderr, "strategy:check_config_interval = [%d]\n"
			"strategy:generate_file_period = [%s]\n"
			"strategy:count = [%d]\n"
			"strategy:file_name = [%s]\n"
			"strategy:single_file_size = [%d]\n"
			"strategy:max_rolloever_index = [%d]\n"
			"logrecord:max_len_of_one_record = [%d]\n"
			,
			this->strategy_.check_config_interval_,
			GenerateFilePeriod[this->strategy_.generate_file_period_],
			this->strategy_.period_count_,
			this->strategy_.file_name_,
			this->strategy_.single_file_size_,
			this->strategy_.max_rolloever_index_,
			this->lrecord_cfg_.max_len_of_one_record_);
	fprintf (stderr, "-------------------------------------------\n");
}
